home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / i8250.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-30  |  19.8 KB  |  897 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * 16550A support plus some statistics added mah@hpuviea.at 15/7/89
  5.  *
  6.  * CTS hardware flow control from dkstevens@ucdavis,
  7.  * additional stats from delaroca@oac.ucla.edu added by karn 4/17/90
  8.  * Feb '91      RLSD line control reorganized by Bill_Simpson@um.cc.umich.edu
  9.  * Sep '91      All control signals reorganized by Bill Simpson
  10.  * Jan '92      Added force 16550 fifo command
  11.  *
  12.  * Mods by PA0GRI
  13.  */
  14. #include <stdio.h>
  15. #include <dos.h>
  16. #include "global.h"
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "iface.h"
  20. #include "i8250.h"
  21. #include "asy.h"
  22. #include "devparam.h"
  23. #include "pc.h"
  24. #include "config.h"
  25.  
  26. #ifdef TIPMAIL
  27. extern struct suspended {
  28.     struct iface *ifp;
  29.     unsigned timeout;
  30.     char modem;
  31. } Tipsuspended[ASY_MAX];
  32. #include "cmdparse.h"
  33. extern struct cmds far Cmds[];
  34. #endif
  35.  
  36. static void asy_monitor __ARGS((int dev,void *p1,void *p2));
  37.  
  38. static void asy_output __ARGS((int dev,char *buf,unsigned short cnt));
  39. static int asyrxint __ARGS((struct asy *asyp));
  40. static void asytxint __ARGS((int dev));
  41. static void asymsint __ARGS((int dev));
  42.  
  43. static void asy_tx __ARGS((int dev,void *p1,void *p2));
  44.  
  45. struct asy Asy[ASY_MAX];
  46.  
  47. /* ASY interrupt handlers */
  48. static INTERRUPT (*Handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  49. static unsigned char fifo_setup;
  50.  
  51.  
  52. /* Initialize asynch port "dev" */
  53. int
  54. asy_init(dev,ifp,arg1,arg2,bufsize,trigchar,monitor,speed,force,triglevel)
  55. int dev;
  56. struct iface *ifp;
  57. char *arg1,*arg2;    /* Attach args for address and vector */
  58. int16 bufsize;
  59. int trigchar;
  60. char monitor;
  61. long speed;
  62. int force;
  63. int triglevel;
  64. {
  65.     register unsigned base;
  66.     register struct fifo *fp;
  67.     register struct asy *ap;
  68.     char *ifn;
  69.     char i_state;
  70.  
  71.     ap = &Asy[dev];
  72.     ap->iface = ifp;
  73.     ap->addr = htoi(arg1);
  74.     ap->vec = htoi(arg2);
  75.  
  76.     /* Set up receiver FIFO */
  77.     fp = &ap->fifo;
  78.     fp->buf = mallocw(bufsize);
  79.     fp->bufsize = bufsize;
  80.     fp->wp = fp->rp = fp->buf;
  81.     fp->cnt = 0;
  82.     fp->hiwat = 0;
  83.     fp->overrun = 0;
  84.     base = ap->addr;
  85.     ap->trigchar = trigchar;
  86.  
  87.     /* Purge the receive data buffer */
  88.     (void)inportb(base+RBR);
  89.  
  90.     i_state = dirps();
  91.  
  92.     /* Save original interrupt vector, mask state, control bits */
  93.     ap->save.vec = getirq(ap->vec);
  94.     ap->save.mask = getmask(ap->vec);
  95.     ap->save.lcr = inportb(base+LCR);
  96.     ap->save.ier = inportb(base+IER);
  97.     ap->save.mcr = inportb(base+MCR);
  98.     ap->save.msr = inportb(base+MSR);
  99.     ap->save.iir = inportb(base+IIR);
  100.  
  101.     /* save speed bytes */
  102.     setbit(base+LCR,LCR_DLAB);
  103.     ap->save.divl = inportb(base+DLL);
  104.     ap->save.divh = inportb(base+DLM);
  105.     clrbit(base+LCR,LCR_DLAB);
  106.  
  107.     /* save some information on the starting state */
  108.     ap->cts_flow_control = (ap->save.msr & MSR_CTS) ? FOUND_UP : FOUND_DOWN;
  109.     ap->rlsd_line_control = (ap->save.msr & MSR_RLSD) ? FOUND_UP : FOUND_DOWN;
  110.     ap->dtr_usage = (ap->save.mcr & MCR_DTR) ? FOUND_UP : FOUND_DOWN;
  111.     ap->rts_usage = (ap->save.mcr & MCR_RTS) ? FOUND_UP : FOUND_DOWN;
  112.  
  113.     /* Set interrupt vector to SIO handler */
  114.     setirq(ap->vec,Handle[dev]);
  115.  
  116.     /* Set line control register: 8 bits, no parity */
  117.     outportb(base+LCR,(char)LCR_8BITS);
  118.  
  119.     /* determine if 16550A, turn on FIFO mode and clear RX and TX FIFOs */
  120.     outportb(base+FCR,(char) FIFO_ENABLE);
  121.  
  122.     /* According to National ap note AN-493, the FIFO in the 16550 chip
  123.      * is broken and must not be used. To determine if this is a 16550A
  124.      * (which has a good FIFO implementation) check that both bits 7
  125.      * and 6 of the IIR are 1 after setting the fifo enable bit. If
  126.      * not, don't try to use the FIFO.
  127.      */
  128.     /* Set the fifo trigger level according to the user's wishes :-) - WG7J */
  129.     if(triglevel == 1)
  130.         fifo_setup = FIFO_SETUP1;
  131.     else if(triglevel == 4)
  132.         fifo_setup = FIFO_SETUP4;
  133.     else if(triglevel == 8)
  134.         fifo_setup = FIFO_SETUP8;
  135.     else if(triglevel == 14)
  136.         fifo_setup = FIFO_SETUP14;
  137.     else
  138.         fifo_setup = FIFO_SETUP4;    /* default to 4 */
  139.  
  140.     if (((inportb(base+IIR) & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED) || force) {
  141.         ap->is_16550a = TRUE;
  142.         outportb(base+FCR,fifo_setup);
  143.     } else {
  144.         /* Chip is not a 16550A. In case it's a 16550 (which
  145.          * has a broken FIFO), turn off the FIFO bit.
  146.          */
  147.         outportb(base+FCR,(char)0);
  148.         ap->is_16550a = FALSE;
  149.     }
  150.  
  151.     /* Turn on modem status and receive interrupts,
  152.      * leave transmit interrupts off for now.
  153.      */
  154.     outportb(base+IER, (char)(IER_MS + IER_DAV));
  155.  
  156.     /* Turn on 8250 master interrupt enable (connected to OUT2) */
  157.     setbit(base+MCR,(MCR_OUT2));
  158.  
  159.     /* Enable interrupt */
  160.     maskon(ap->vec);
  161.     restore(i_state);
  162.  
  163.     asy_speed(dev,speed);
  164.  
  165.     if ( monitor ) {
  166.         /* set up to monitor line signals */
  167.         ap->monitor = newproc( ifn = if_name( ifp, " monitor" ),
  168.                 256, asy_monitor, ifp->dev, ifp, NULL, 0);
  169.         free(ifn);
  170.         pwait(NULL);    /* let hooks get set up */
  171.     }
  172.  
  173.     ifp->txproc = newproc( ifn = if_name(ifp," tx"),
  174.             256, asy_tx, dev, ifp, NULL, 0);
  175.     free(ifn);
  176.  
  177.     if ( (ap->dtr_usage & FOUND_UP)
  178.       && (ap->rlsd_line_control & FOUND_UP)
  179.      || ap->monitor == NULL ) {
  180.         if ( ifp->iostatus != NULL ) {
  181.             (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  182.         }
  183.     }
  184.     return 0;
  185. }
  186.  
  187.  
  188. int
  189. asy_stop(ifp)
  190. struct iface *ifp;
  191. {
  192.     register unsigned base;
  193.     register struct asy *ap;
  194.     char i_state;
  195.  
  196.     ap = &Asy[ifp->dev];
  197.  
  198.     if ( ap->monitor != NULL ) {
  199.         ap->rlsd_line_control = IGNORED;
  200.         killproc( ap->monitor );
  201.         ap->monitor = NULL;
  202.     }
  203.     ap->iface = NULLIF;
  204.  
  205.     base = ap->addr;
  206.  
  207.     /* Purge the receive data buffer */
  208.     (void)inportb(base+RBR);
  209.  
  210.     /* and hardware fifos if available */
  211.     if (ap->is_16550a) {
  212.         if((ap->save.iir & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED)
  213.             outportb(base+FCR,fifo_setup);
  214.         else
  215.             outportb(base+FCR,0);
  216.     }
  217.  
  218.     /* Restore original interrupt vector and 8259 mask state */
  219.     i_state = dirps();
  220.     setirq(ap->vec,ap->save.vec);
  221.     if(ap->save.mask)
  222.         maskon(ap->vec);
  223.     else
  224.         maskoff(ap->vec);
  225.  
  226.     /* Restore speed regs */
  227.     setbit(base+LCR,LCR_DLAB);
  228.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  229.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  230.     clrbit(base+LCR,LCR_DLAB);
  231.  
  232.     /* Restore control regs */
  233.     /* except, leave DTR in current state {bsimpson} */
  234.     outportb(base+LCR,ap->save.lcr);
  235.     outportb(base+IER,ap->save.ier);
  236.     outportb(base+MCR,ap->save.mcr);
  237. #ifdef notdef
  238.     outportb(base+MCR,(ap->save.mcr &~ MCR_DTR)
  239.             | (inportb(base+MCR) & MCR_DTR) );
  240. #endif
  241.  
  242.     restore(i_state);
  243.     free(ap->fifo.buf);
  244.     return 0;
  245. }
  246.  
  247.  
  248. /* Set asynch line speed */
  249. int
  250. asy_speed(dev,bps)
  251. int dev;
  252. long bps;
  253. {
  254.     register unsigned base;
  255.     register long divisor;
  256.     struct asy *asyp;
  257.     char i_state;
  258.  
  259.     if(bps <= 0 || dev >= ASY_MAX)
  260.         return -1;
  261.     asyp = &Asy[dev];
  262.     if(asyp->iface == NULLIF)
  263.         return -1;
  264.  
  265.     switch(bps) {
  266.     case 300:
  267.     case 1200:
  268.     case 2400:
  269.     case 4800:
  270.     case 9600:
  271.     case 19200:
  272.     case 38400L:
  273.     case 56700L:
  274.     case 115200L:
  275.         /* supported speed */
  276.         asyp->speed = bps;
  277.         break;
  278.     default:
  279.         /* unsupported speed */
  280.         return -1;
  281.     };
  282.  
  283.     base = asyp->addr;
  284.     divisor = BAUDCLK / bps;
  285.  
  286.     i_state = dirps();
  287.  
  288.     /* Purge the receive data buffer */
  289.     (void)inportb(base+RBR);
  290.     if (asyp->is_16550a)        /* clear tx+rx fifos */
  291.         outportb(base+FCR,fifo_setup);
  292.  
  293.     /* Turn on divisor latch access bit */
  294.     setbit(base+LCR,LCR_DLAB);
  295.  
  296.     /* Load the two bytes of the register */
  297.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  298.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  299.  
  300.     /* Turn off divisor latch access bit */
  301.     clrbit(base+LCR,LCR_DLAB);
  302.  
  303.     restore(i_state);
  304.     return 0;
  305. }
  306.  
  307.  
  308. /* Asynchronous line I/O control */
  309. int32
  310. asy_ioctl(ifp,cmd,set,val)
  311. struct iface *ifp;
  312. int cmd;
  313. int set;
  314. int32 val;
  315. {
  316.     struct asy *ap = &Asy[ifp->dev];
  317.     int16 base = ap->addr;
  318.  
  319.     switch(cmd){
  320.     case PARAM_SPEED:
  321.         if(set)
  322.             asy_speed(ifp->dev,val);
  323.         return ap->speed;
  324.     case PARAM_DTR:
  325.         if(set) {
  326.             writebit(base+MCR,MCR_DTR,(int)val);
  327.             ap->dtr_usage = (val) ? MOVED_UP : MOVED_DOWN;
  328.         }
  329.         return (inportb(base+MCR) & MCR_DTR) ? TRUE : FALSE;
  330.     case PARAM_RTS:
  331.         if(set) {
  332.             writebit(base+MCR,MCR_RTS,(int)val);
  333.             ap->rts_usage = (val) ? MOVED_UP : MOVED_DOWN;
  334.         }
  335.         return (inportb(base+MCR) & MCR_RTS) ? TRUE : FALSE;
  336.     case PARAM_DOWN:
  337.         clrbit(base+IER,(char)IER_DAV);
  338.         clrbit(base+MCR,MCR_RTS);
  339.         clrbit(base+MCR,MCR_DTR);
  340.         ap->rts_usage = MOVED_DOWN;
  341.         ap->dtr_usage = MOVED_DOWN;
  342.         return FALSE;
  343.     case PARAM_UP:
  344.         setbit(base+IER,(char)IER_DAV);
  345.         setbit(base+MCR,MCR_RTS);
  346.         setbit(base+MCR,MCR_DTR);
  347.         ap->rts_usage = MOVED_UP;
  348.         ap->dtr_usage = MOVED_UP;
  349.         return TRUE;
  350.     case PARAM_BLIND:
  351.         setbit(base+IER,(char)IER_DAV);
  352.         ap->rlsd_line_control = IGNORED;
  353.  
  354.         if ( ap->monitor != NULL ) {
  355.             killproc( ap->monitor );
  356.             ap->monitor = NULL;
  357.         }
  358.  
  359.         /* can't see what we are doing, so pretend we're up */
  360.         if ( ifp->iostatus != NULL ) {
  361.             (*ifp->iostatus)(ifp, PARAM_UP, 0L);
  362.         }
  363.         return TRUE;
  364.     };
  365.     return -1;
  366. }
  367.  
  368.  
  369. /* Start transmission of a buffer on the serial transmitter */
  370. static void
  371. asy_output(dev,buf,cnt)
  372. int dev;
  373. char *buf;
  374. unsigned short cnt;
  375. {
  376.     register struct dma *dp;
  377.     unsigned base;
  378.     char i_state;
  379.     char ier;
  380.     struct asy *asyp;
  381.  
  382.     if(dev < 0 || dev >= ASY_MAX)
  383.         return;
  384.     asyp = &Asy[dev];
  385.     if(asyp->iface == NULLIF)
  386.         return;
  387.  
  388.     base = asyp->addr;
  389.     dp = &asyp->dma;
  390.     i_state = dirps();
  391.  
  392.     if(dp->flags){
  393.         restore(i_state);
  394.         return;    /* Already busy */
  395.     }
  396.     dp->data = buf;
  397.     dp->cnt = cnt;
  398.     dp->flags = 1;
  399.  
  400.     if(asyp->cts_flow_control & MOVED_DOWN){
  401.         /* CTS flow control is enabled; let the modem control
  402.          * interrupt enable transmit interrupts if CTS is off
  403.          */
  404.         ier = IER_MS;
  405.         if(inportb(base+MSR) & MSR_CTS)
  406.             ier |= IER_TxE;
  407.     } else {
  408.         /* Enable transmit interrupts; this will cause an immediate
  409.          * interrupt that will start things going
  410.          */
  411.         ier = IER_TxE;
  412.     }
  413.     setbit(base+IER,ier);
  414.  
  415.     /* "Kick start" the transmitter interrupt routine, in case just
  416.      * setting the interrupt enable bit doesn't cause an interrupt
  417.      */
  418.     if(ier & IER_TxE)
  419.         asytxint(dev);
  420.     restore(i_state);
  421. }
  422.  
  423.  
  424. /* Blocking read from asynch line
  425.  * Returns character or -1 if aborting
  426.  * Returns -2 (CD_DOWN) if carrier checking is on and dropped
  427.  */
  428. int
  429. get_asy(dev)
  430. int dev;
  431. {
  432.     char i_state;
  433.     register struct fifo *fp;
  434.     char c;
  435.  
  436.     fp = &Asy[dev].fifo;
  437.  
  438.     i_state = dirps();
  439.     while(fp->cnt == 0){
  440.         if(pwait(fp) != 0){
  441.             restore(i_state);
  442.             return -1;
  443.         }
  444.     }
  445.     fp->cnt--;
  446.     restore(i_state);
  447.  
  448.     c = *fp->rp++;
  449.     if(fp->rp >= &fp->buf[fp->bufsize])
  450.         fp->rp = fp->buf;
  451.  
  452.     return uchar(c);
  453. }
  454.  
  455.  
  456. /* Interrupt handler for 8250 asynch chip (called from asyvec.asm) */
  457. void
  458. asyint(dev)
  459. int dev;
  460. {
  461.     struct asy *asyp;
  462.     unsigned base;
  463.     char iir;
  464.  
  465.     asyp = &Asy[dev];
  466.     base = asyp->addr;
  467.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  468.         switch(iir & IIR_ID_MASK){
  469.         case IIR_RDA:    /* Receiver interrupt */
  470.             asyrxint(asyp);
  471.             break;
  472.         case IIR_THRE:    /* Transmit interrupt */
  473.             asytxint(dev);
  474.             break;
  475.         case IIR_MSTAT:    /* Modem status change */
  476.             asymsint(dev);
  477.             asyp->msint_count++;
  478.             break;
  479.         }
  480.         /* should happen at end of a single packet */
  481.         if(iir & IIR_FIFO_TIMEOUT)
  482.             asyp->fifotimeouts++;
  483.     }
  484. }
  485.  
  486.  
  487. /* Process 8250 receiver interrupts */
  488. static int
  489. asyrxint(asyp)
  490. struct asy *asyp;
  491. {
  492.     register struct fifo *fp;
  493.     unsigned base;
  494.     char c,lsr;
  495.     int cnt = 0;
  496.     int trigseen = FALSE;
  497.  
  498.     asyp->rxints++;
  499.     base = asyp->addr;
  500.     fp = &asyp->fifo;
  501.     for(;;){
  502.         lsr = inportb(base+LSR);
  503.         if(lsr & LSR_OE)
  504.             asyp->overrun++;
  505.  
  506.         if(lsr & LSR_DR){
  507.             asyp->rxchar++;
  508.             c = inportb(base+RBR);
  509.             if(asyp->trigchar == uchar(c))
  510.                 trigseen = TRUE;
  511.             /* If buffer is full, we have no choice but
  512.              * to drop the character
  513.              */
  514.             if(fp->cnt != fp->bufsize){
  515.                 *fp->wp++ = c;
  516.                 if(fp->wp >= &fp->buf[fp->bufsize])
  517.                     /* Wrap around */
  518.                     fp->wp = fp->buf;
  519.                 fp->cnt++;
  520.                 if(fp->cnt > fp->hiwat)
  521.                     fp->hiwat = fp->cnt;
  522.                 cnt++;
  523.             } else
  524.                 fp->overrun++;
  525.         } else
  526.             break;
  527.     }
  528.     if(cnt > asyp->rxhiwat)
  529.         asyp->rxhiwat = cnt;
  530.     if(trigseen)
  531.         psignal(fp,1);
  532.     return cnt;
  533. }
  534.  
  535.  
  536. /* Handle 8250 transmitter interrupts */
  537. static void
  538. asytxint(dev)
  539. int dev;
  540. {
  541.     register struct dma *dp;
  542.     register unsigned base;
  543.     register int count;
  544.     struct asy *asyp;
  545.  
  546.     asyp = &Asy[dev];
  547.     base = asyp->addr;
  548.     dp = &asyp->dma;
  549.     asyp->txints++;
  550.     if(!dp->flags){
  551.         /* "Shouldn't happen", but disable transmit
  552.          * interrupts anyway
  553.          */
  554.         clrbit(base+IER,IER_TxE);
  555.         return;    /* Nothing to send */
  556.     }
  557.     if(!(inportb(base+LSR) & LSR_THRE))
  558.         return;    /* Not really ready */
  559.  
  560.     /* If it's a 16550A, load up to 16 chars into the tx hw fifo
  561.      * at once. With an 8250, it can be one char at most.
  562.      */
  563.     if(asyp->is_16550a){
  564.         count = min(dp->cnt,OUTPUT_FIFO_SIZE);
  565.  
  566.         /* 16550A: LSR_THRE will drop after the first char loaded
  567.          * so we can't look at this bit to determine if the hw fifo is
  568.          * full. There seems to be no way to determine if the tx fifo
  569.          * is full (any clues?). So we should never get here while the
  570.          * fifo isn't empty yet.
  571.          */
  572.         asyp->txchar += count;
  573.         dp->cnt -= count;
  574. #ifdef    notdef    /* This is apparently too fast for some chips */
  575.         dp->data = outbuf(base+THR,dp->data,count);
  576. #else
  577.         while(count-- != 0)
  578.             outportb(base+THR,*dp->data++);
  579. #endif
  580.         if(dp->cnt == 0){
  581.             dp->flags = 0;
  582.             /* Disable transmit interrupts */
  583.             clrbit(base+IER,IER_TxE);
  584.             psignal(asyp,1);
  585.         }
  586.     } else {    /* 8250 */
  587.         do {
  588.             asyp->txchar++;
  589.             outportb(base+THR,*dp->data++);
  590.  
  591.             if(--dp->cnt == 0){
  592.                 dp->flags = 0;
  593.                 /* Disable transmit interrupts */
  594.                 clrbit(base+IER,IER_TxE);
  595.                 psignal(asyp,1);
  596.                 break;
  597.             }
  598.         } while(inportb(base+LSR) & LSR_THRE);
  599.     }
  600. }
  601.  
  602.  
  603. /* Handle 8250 modem status change
  604.  *    If the signals are unchanging, we ignore them.
  605.  *    If they change, we use them to condition the line.
  606.  */
  607. static void
  608. asymsint(dev)
  609. int dev;
  610. {
  611.     struct asy *ap = &Asy[dev];
  612.     unsigned base = ap->addr;
  613.  
  614.     ap->msr = inportb(base+MSR);
  615.  
  616.     if ( ap->msr & MSR_CTS ) {
  617.         switch ( ap->cts_flow_control ) {
  618.         case FOUND_DOWN:
  619.         case MOVED_DOWN:
  620.             ap->cts_flow_control = MOVED_UP;
  621.  
  622.             /* CTS now asserted, enable Transmit interrupts */
  623.             if(ap->dma.flags)
  624.                 setbit(base+IER,IER_TxE);
  625.             break;
  626.         };
  627.     } else {
  628.         switch ( ap->cts_flow_control ) {
  629.         case FOUND_UP:
  630.         case MOVED_UP:
  631.             ap->cts_flow_control = MOVED_DOWN;
  632.  
  633.             /* CTS now dropped, disable Transmit interrupts */
  634.             clrbit(base+IER,IER_TxE);
  635.             break;
  636.         };
  637.     }
  638.  
  639.     if ( ap->msr & MSR_RLSD ) {
  640.         switch ( ap->rlsd_line_control ) {
  641.         case FOUND_DOWN:
  642.         case MOVED_DOWN:
  643.             ap->rlsd_line_control = MOVED_UP;
  644.  
  645.             /* RLSD just went up */
  646.             psignal( &(ap->rlsd_line_control), 1 );
  647.             break;
  648.         };
  649.     } else {
  650.         switch ( ap->rlsd_line_control ) {
  651.         case FOUND_UP:
  652.         case MOVED_UP:
  653.             ap->rlsd_line_control = MOVED_DOWN;
  654.  
  655.             /* RLSD just went down */
  656.             psignal( &(ap->rlsd_line_control), 1 );
  657.             break;
  658.         };
  659.     }
  660.  
  661.     if ( ap->msr & (MSR_TERI | MSR_RI) ) {
  662.         asy_ioctl( ap->iface, PARAM_UP, TRUE, 0L );
  663.     }
  664. }
  665.  
  666.  
  667. /* Wait for a signal that the RLSD modem status has changed */
  668. int
  669. get_rlsd_asy(dev, new_rlsd)
  670. int dev;
  671. int new_rlsd;
  672. {
  673.     struct asy *ap = &Asy[dev];
  674.     struct iface *ifp = ap->iface;
  675.     int result;
  676.  
  677.     if ( ap->rlsd_line_control & IGNORED ) {
  678.         return IGNORED;
  679.     }
  680.  
  681.     switch ( new_rlsd ) {
  682.     case IGNORED:
  683.         /* Just return the current value */
  684.         return(ap->rlsd_line_control);
  685.  
  686.     case MOVED_DOWN:
  687.         if ( !(ap->rlsd_line_control & FOUND_UP) ) {
  688.             /* Already at requested value */
  689.             return(new_rlsd);
  690.         }
  691.         break;
  692.     case MOVED_UP:
  693.         if ( ap->rlsd_line_control & FOUND_UP ) {
  694.             /* Already at requested value */
  695.             return(new_rlsd);
  696.         }
  697.         break;
  698.     };
  699.  
  700.     /* Wait for state change to requested value */
  701.     while (ap->rlsd_line_control != new_rlsd) {
  702.         mspause(2L);
  703.         pwait( &(ap->rlsd_line_control) );
  704.     }
  705.  
  706.     if ( ap->rlsd_line_control & FOUND_UP )
  707.         result = PARAM_UP;
  708.     else /* DOWN or IGNORED */
  709.         result = PARAM_DOWN;
  710.  
  711.     /* set our control signals to follow RLSD */
  712.     if ( ifp->ioctl != NULL )
  713.         (*ifp->ioctl)( ifp, result, TRUE, 0L );
  714.     if ( ifp->iostatus != NULL )
  715.         (*ifp->iostatus)( ifp, result, 0L );
  716.     return(ap->rlsd_line_control);
  717. }
  718.  
  719.  
  720. /* Monitor RLSD signal, and report status changes */
  721. static void
  722. asy_monitor( dev, p1, p2 )
  723. int dev;
  724. void *p1;
  725. void *p2;
  726. {
  727.     int save_rlsd = Asy[dev].rlsd_line_control;
  728.  
  729.     while ( save_rlsd != IGNORED ) {
  730.         save_rlsd = get_rlsd_asy( dev,
  731.             ( save_rlsd ^ FOUND_UP ) | MOVED_DOWN );
  732.     }
  733.     Asy[dev].monitor = NULL;
  734. }
  735.  
  736.  
  737. /* Poll the asynch input queues; called on every clock tick.
  738.  * This helps limit the interrupt ring buffer occupancy when long
  739.  * packets are being received.
  740.  */
  741. void
  742. asytimer()
  743. {
  744. register struct asy *asyp;
  745. register struct fifo *fp;
  746. register int i;
  747.  
  748.     for(i=0;i<ASY_MAX;i++){
  749.         asyp = &Asy[i];
  750.         fp = &asyp->fifo;
  751.         if(fp->cnt != 0)
  752.             psignal(fp,1);
  753.         if(asyp->dma.flags != 0 && (inportb(asyp->addr+LSR) & LSR_THRE) \
  754.                                 /* transmit interrupt should be on !,
  755.                                  * ie no flow control */
  756.                                 && (inportb(asyp->addr+IER) & IER_TxE) ){
  757.             asyp->txto++;
  758.             asytxint(asyp->iface->dev);
  759.         }
  760. #ifdef TIPMAIL
  761.         if (Tipsuspended[i].ifp)    {
  762.             if (!carrier_detect(i))    {
  763.                 char buf[40];
  764.                 sprintf (buf, "start tip %s %s %d\n", Tipsuspended[i].ifp->name, (Tipsuspended[i].modem) ? "m" : "t", Tipsuspended[i].timeout);
  765.                 cmdparse(Cmds,buf,NULL);
  766.                 Tipsuspended[i].ifp = 0;
  767.                 Tipsuspended[i].modem = 0;
  768.                 Tipsuspended[i].timeout = 0;
  769.             }
  770.         }
  771. #endif
  772.     }
  773. }
  774.  
  775.  
  776. int
  777. doasystat(argc,argv,p)
  778. int argc;
  779. char *argv[];
  780. void *p;
  781. {
  782.     register struct asy *asyp;
  783.  
  784.     for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  785.         if(asyp->iface == NULLIF)
  786.             continue;
  787.  
  788.         tprintf("%s:",asyp->iface->name);
  789.         if(asyp->is_16550a)
  790.             tprintf(" [NS16550A]");
  791.         if(asyp->trigchar != -1)
  792.             tprintf(" [trigger 0x%02x]",asyp->trigchar);
  793.         switch (asyp->cts_flow_control) {
  794.         case MOVED_DOWN:
  795.         case MOVED_UP:
  796.             tprintf(" [cts flow control]");
  797.             break;
  798.         };
  799.         switch (asyp->rlsd_line_control) {
  800.         case MOVED_DOWN:
  801.         case MOVED_UP:
  802.             tprintf(" [rlsd line control]");
  803.             break;
  804.         case IGNORED:
  805.             tprintf(" [blind]");
  806.             break;
  807.         };
  808.         tprintf(" %lu bps\n",asyp->speed);
  809.  
  810.         tprintf(" RX: %lu int, %lu chr, %lu hw over, %lu hw hi,",
  811.             asyp->rxints,
  812.             asyp->rxchar,
  813.             asyp->overrun,
  814.             asyp->rxhiwat);
  815.         asyp->rxhiwat = 0;
  816.         if(asyp->is_16550a)
  817.             tprintf(" %lu fifo TO,",asyp->fifotimeouts);
  818.         tprintf(" %lu sw over, %u sw hi\n",
  819.             asyp->fifo.overrun,
  820.             asyp->fifo.hiwat);
  821.         asyp->fifo.hiwat = 0;
  822.  
  823.         if(tprintf(" TX: %lu int, %lu chr, %u q, %lu MS int, %lu THRE TO\n",
  824.             asyp->txints,
  825.             asyp->txchar,
  826.             len_q(asyp->sndq),
  827.             asyp->msint_count,
  828.             asyp->txto) == EOF)
  829.             break;
  830.     }
  831.     return 0;
  832. }
  833. /* Send a message on the specified serial line */
  834. int
  835. asy_send(dev,bp)
  836. int dev;
  837. struct mbuf *bp;
  838. {
  839.     if(dev < 0 || dev >= ASY_MAX)
  840.         return -1;
  841.     enqueue(&Asy[dev].sndq,bp);
  842.     return 0;
  843. }
  844.  
  845. /* Serial transmit process, common to all protocols */
  846. static void
  847. asy_tx(dev,p1,p2)
  848. int dev;
  849. void *p1;
  850. void *p2;
  851. {
  852.     register struct mbuf *bp;
  853.     struct asy *asyp;
  854.     struct dma *dp;
  855.     int i_state;
  856.  
  857.     asyp = &Asy[dev];
  858.     dp = &asyp->dma;
  859.  
  860.     for(;;){
  861.         /* Fetch a buffer for transmission */
  862.         while(asyp->sndq == NULLBUF)
  863.             pwait(&asyp->sndq);
  864.  
  865.         bp = dequeue(&asyp->sndq);
  866.  
  867.         while(bp != NULLBUF){
  868.             /* Start the transmitter */
  869.             asy_output(dev,bp->data,bp->cnt);
  870.  
  871.             /* Wait for completion */
  872.             i_state = dirps();
  873.             while(dp->flags == 1)
  874.                 pwait(asyp);
  875.             restore(i_state);
  876.  
  877.             /* Now do next buffer on chain */
  878.             bp = free_mbuf(bp);
  879.         }
  880.     }
  881. }
  882.  
  883. int
  884. carrier_detect(int dev)
  885. {
  886.     struct asy *ap = &Asy[dev];
  887.     unsigned base = ap->addr;
  888.  
  889.     ap->msr = inportb(base+MSR);
  890.     if ( ap->msr & MSR_RLSD ) {
  891.          return 1;
  892.     } else {
  893.          return 0;
  894.     }
  895. }
  896.  
  897.